package com.xxl.job.core.thread;

import com.xxl.job.core.Constant;
import com.xxl.job.core.biz.AdminBiz;
import com.xxl.job.core.biz.model.RegistryParam;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.enums.RegistTypeEnum;
import com.xxl.job.core.executor.XxlJobExecutor;
import com.xxl.job.core.util.IpUtil;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
/**
 * 每30s向调度中心发送心跳一次，注册自己
 * Created by xuxueli on 17/3/2.
 */
@Slf4j
public class ExecutorRegistryThread {
	
    private static ExecutorRegistryThread instance = new ExecutorRegistryThread();
    public static ExecutorRegistryThread getInstance(){
        return instance;
    }

    
    
    
    private Thread registryThread;
    private volatile boolean toStop = false;
    
    public void start(final int port, final String ip, final String appName){
        // valid
        if (appName==null || appName.trim().length()==0) {
            log.warn(">>>>>>>>>>> xxl-job, executor registry config fail, appName is null.");
            return;
        }
        if (XxlJobExecutor.getAdminBizs() == null) {
            log.warn(">>>>>>>>>>> xxl-job, executor registry config fail, adminAddresses is null.");
            return;
        }

        // executor address (generate addredd = ip:port)
        final String executorAddress;
        if (ip != null && ip.trim().length()>0) {
            executorAddress = ip.trim().concat(":").concat(String.valueOf(port));
        }
        else {
            executorAddress = IpUtil.getIpPort(port);
        }

        registryThread = new Thread(new Runnable() {
            @Override
            public void run() {
                // registry
                while (!toStop) {
                	//每30s向调度中心注册执行器信息
                    try {
                        RegistryParam registryParam = new RegistryParam(RegistTypeEnum.EXECUTOR.name(),
                        		appName,
                        		executorAddress);
                        
                        for (AdminBiz adminBiz : XxlJobExecutor.getAdminBizs()) {
                            try {
                                ReturnT<String> registryResult = adminBiz.registry(registryParam);
                                if (registryResult!=null && ReturnT.SUCCESS_CODE == registryResult.getCode()) {
                                    registryResult = ReturnT.SUCCESS;
                                    log.info(">>>>>>>>>>> xxl-job registry success, registryParam:{}, registryResult:{}", new Object[]{registryParam, registryResult});
                                    break;
                                } 
                                else {
                                    log.info(">>>>>>>>>>> xxl-job registry fail, registryParam:{}, registryResult:{}", new Object[]{registryParam, registryResult});
                                }
                            } 
                            catch (Exception e) {
                                log.info(">>>>>>>>>>> xxl-job registry error, registryParam:{}", registryParam, e);
                            }
                        }
                    } catch (Exception e) {
                        log.error(e.getMessage(), e);
                    }

                    try {
                        TimeUnit.SECONDS.sleep(Constant.BEAT_TIMEOUT);
                    } catch (InterruptedException e) {
                        log.error(e.getMessage(), e);
                    }
                }

                
                // registry remove
                try {
                    RegistryParam registryParam = new RegistryParam(RegistTypeEnum.EXECUTOR.name(),
                    		appName,
                    		executorAddress);
                    
                    //从调度中心移除执行器信息
                    for (AdminBiz adminBiz : XxlJobExecutor.getAdminBizs()) {
                        try {
                            ReturnT<String> registryResult = adminBiz.registryRemove(registryParam);
                            if (registryResult!=null && ReturnT.SUCCESS_CODE == registryResult.getCode()) {
                                registryResult = ReturnT.SUCCESS;
                                log.info(">>>>>>>>>>> xxl-job registry-remove success, registryParam:{}, registryResult:{}", new Object[]{registryParam, registryResult});
                                break;
                            }
                            else {
                                log.info(">>>>>>>>>>> xxl-job registry-remove fail, registryParam:{}, registryResult:{}", new Object[]{registryParam, registryResult});
                            }
                        }
                        catch (Exception e) {
                            log.info(">>>>>>>>>>> xxl-job registry-remove error, registryParam:{}", registryParam, e);
                        }
                    }
                }
                catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
                log.info(">>>>>>>>>>> xxl-job, executor registry thread destory.");
            }
        });
        
        registryThread.setDaemon(true);
        registryThread.start();
    }

    public void toStop() {
        toStop = true;
        // interrupt and wait
        registryThread.interrupt();
        try {
            registryThread.join();
        }
        catch (InterruptedException e) {
            log.error(e.getMessage(), e);
        }
        
    }
}